package com.api.apigateway.risk;

/**
 * 特征提取
 * 运行逻辑：把请求上下文 + 时序统计转换为稳定的数值特征，供模型与规则使用。
 */
public class FeatureExtractor {

    private final SlidingWindowStats win;

    public FeatureExtractor(SlidingWindowStats win){ this.win = win; }

    /** 统一提取特征（顺序需与训练保持一致） */
    public FeatureVector extract(RiskContext c){
        FeatureVector fv = new FeatureVector();

        // —— 请求侧 —— 
        fv.put("method_get", "GET".equalsIgnoreCase(c.method)?1:0);
        fv.put("method_post", "POST".equalsIgnoreCase(c.method)?1:0);
        fv.put("header_cnt", c.headers==null? 0 : c.headers.size());
        fv.put("ua_len", c.ua==null? 0 : c.ua.length());
        fv.put("query_size", c.querySizeBytes);
        fv.put("body_size", c.bodySizeBytes);
        fv.put("param_cnt", c.paramCount);
        fv.put("is_ak_present", c.ak==null?0:1);

        // —— 账号侧 —— 
        fv.put("has_user", c.userId==null?0:1);
        fv.put("user_mod_10", c.userId==null?0:(c.userId%10)); // 粗暴离散（训练需一致）
        fv.put("path_hash_mod_100", (c.path==null?0:Math.abs(c.path.hashCode()%100)));

        // —— 时序侧 —— 
        double qps_u_p = win.getQps(c.userId, c.ak, c.ip, c.path);
        double delta_u_p = win.getDelta(c.userId, c.ak, c.ip, c.path);
        double H_ip = win.getEntropyApprox(c.ip);

        fv.put("qps_user_path", qps_u_p);
        fv.put("delta_user_path", delta_u_p);
        fv.put("entropy_ip", H_ip);

        // —— 简单指纹 —— 
        fv.put("ip_hash_mod_1000", c.ip==null?0:Math.abs(c.ip.hashCode()%1000));
        fv.put("ua_hash_mod_1000", c.ua==null?0:Math.abs(c.ua.hashCode()%1000));

        return fv;
    }

    /** 路径模板归一（/api/weather/shanghai -> /api/weather/{city}），示意 */
    public static String normalizePath(String raw){
        if (raw==null) return "/";
        // 把数字段、UUID、大写英文字母段，视为变量
        String s = raw.replaceAll("/[0-9]+", "/{num}")
                      .replaceAll("/[0-9a-fA-F\\-]{8,}", "/{id}")
                      .replaceAll("/[A-Z][A-Za-z0-9_]*", "/{var}");
        return s;
    }
}